import re
import traceback

from django.contrib.auth.decorators import permission_required
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from rest_framework.decorators import permission_classes
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

from monitor_web import models
from monitor_web.serializers import TriggerFunctionSerializer2
from web.common import constant
from web.common.paging import paging_request, paging_request2


@permission_classes((IsAuthenticated,))
class TriggerList(APIView):
    @method_decorator(permission_required('monitor_web.view_trigger', raise_exception=True))
    def get(self, request, pk=None, format=None):
        page_data = None
        count = None
        if request.GET.get('template_id') is not None:
            template_id = self.request.query_params['template_id']
            item_ids = []
            for item in models.MonitorItem.objects.filter(template_id=template_id, item_copy_from=0).all():
                item_ids.append(str(item.id))
            # 汇总每个item对应的触发器
            page_data, count = paging_request2(request, models.Trigger, self, extra_where=[
                'id IN (SELECT DISTINCT(trigger_id) FROM `function` WHERE item_id IN (%s))' % ','.join(item_ids)])
        elif request.GET.get('item_id') is not None:
            page_data, count = paging_request2(request, models.Trigger, self, extra_where=[
                'id IN (SELECT DISTINCT(trigger_id) FROM `function` WHERE item_id IN (%s))' % request.GET['item_id']])
        elif request.GET.get('host_id') is not None:
            host_id = request.GET.get('host_id')
            page_data, count = paging_request2(request, models.Trigger, self, extra_where=[
                'id IN (SELECT DISTINCT(trigger_id) FROM `function` WHERE item_id IN (SELECT id FROM monitor.item WHERE host_id = %s))' % host_id])

        # 对数据进行序列化
        serializer = TriggerFunctionSerializer2(instance=page_data, many=True)

        # 字段在Function表外，手动再对trigger_name排序
        # data = sorted(serializer.data, key=lambda kv: kv['trigger_name'],
        #               reverse=param_to_order(request)) if param_to_order(request) is not None else serializer.data
        data = serializer.data
        ret = {
            "code": constant.BACKEND_CODE_OK,
            "data": {
                "count": count,
                "items": data,
                "page": {
                    "currPage": request.GET.get('page', constant.DEFAULT_CURRENT_PAGE),
                    "pageSize": request.GET.get('size', constant.DEFAULT_PAGE_SIZE)
                }
            }
        }
        return JsonResponse(ret, safe=False)


class TriggerInfo(APIView):
    @method_decorator(permission_required('monitor_web.change_trigger', raise_exception=True))
    def get(self, request, pk=None, format=None):
        trigger_id = self.request.query_params['id']
        data = models.Trigger.objects.filter(id=trigger_id).first()
        serializer = TriggerFunctionSerializer2(instance=data, many=False)
        ret = {
            "code": constant.BACKEND_CODE_OK,
            "data": {
                "item": serializer.data
            }
        }
        return JsonResponse(ret, safe=False)

    @method_decorator(permission_required('monitor_web.add_trigger', raise_exception=True))
    def post(self, request, pk=None, format=None):
        data = JSONParser().parse(self.request)
        ret = {
            'code': constant.BACKEND_CODE_OPT_FAIL,
            'message': '创建触发器失败'
        }
        # 匹配触发器中的值
        pattern = re.compile(r'{([^}]*)}(.*)', re.S)
        trigger = None
        db_express = None
        if 'host_id' in data:
            trigger = models.Trigger.objects.create(name=data['name'], expression=data['expression'], template_id=None)
            # https://pythex.org/?regex=%7B(%5B%5E%7D%5D*)%7D%2B&test_string=%7Bproc.num%5B%5D.avg(5m)%7D%3E111%26%7Bscript.google.crawler.num.avg(5m)%7D%3C333&ignorecase=1&multiline=1&dotall=1&verbose=1
            pattern = re.compile(r'{([^}]*)}', re.S)
            # https://pythex.org/?regex=(.(avg%7Clast)%5C((.%5B%5E%5C)%5D*))&test_string=proc.num%5B%5D.avg(5m)&ignorecase=1&multiline=1&dotall=1&verbose=1
            pattern_exp = re.compile(r'(.*).(avg|last)\((.[^\)]*)', re.S)
            data['pattern_exp'] = pattern_exp
            data['trigger_id'] = trigger.id
            db_express = re.sub(pattern, expression_replace_callback4(extra_arg={'data': data}), data['expression'])
            try:
                models.Trigger.objects.filter(id=data['trigger_id']).update(expression=db_express, status=data['enable'], desc=data['desc'], level=data['level'], name=data['name'])
            except:
                print(traceback.format_exc())
                return JsonResponse(ret, safe=False)
        elif 'template_id' in data:
            trigger = models.Trigger.objects.create(name=data['name'], expression=data['expression'], template_id=data['template_id'])
            db_express = re.sub(pattern, expression_replace_callback0(
            extra_arg={'trigger_id': trigger.id, 'template_id': data['template_id']}), data['expression'])
            try:
                models.Trigger.objects.filter(id=trigger.id).update(expression=db_express)
            except:
                print(traceback.format_exc())
                return JsonResponse(ret, safe=False)
        # TODO 这里需要加事务
        ret = {
            'code': constant.BACKEND_CODE_CREATED,
            'message': '创建触发器成功'
        }
        return JsonResponse(ret, safe=False)

    @method_decorator(permission_required('monitor_web.change_trigger', raise_exception=True))
    def put(self, request, pk=None, format=None):
        data = JSONParser().parse(self.request)
        ret = {
            'code': constant.BACKEND_CODE_OPT_FAIL,
            'message': '修改触发器失败'
        }
        # https://pythex.org/?regex=%7B(%5B%5E%7D%5D*)%7D%2B&test_string=%7Bproc.num%5B%5D.avg(5m)%7D%3E111%26%7Bscript.google.crawler.num.avg(5m)%7D%3C333&ignorecase=1&multiline=1&dotall=1&verbose=1
        pattern = re.compile(r'{([^}]*)}', re.S)
        # https://pythex.org/?regex=(.(avg%7Clast)%5C((.%5B%5E%5C)%5D*))&test_string=proc.num%5B%5D.avg(5m)&ignorecase=1&multiline=1&dotall=1&verbose=1
        pattern_exp = re.compile(r'(.*).(avg|last)\((.[^\)]*)', re.S)
        data['pattern_exp'] = pattern_exp

        db_express = re.sub(pattern, expression_replace_callback4(extra_arg={'data': data}), data['expression'])
        print(db_express)
        try:
            models.Trigger.objects.filter(id=data['trigger_id']).update(expression=db_express, status=data['enable'],
                                                                        desc=data['desc'], level=data['level'],
                                                                        name=data['name'])
        except:
            print(traceback.format_exc())
            return JsonResponse(ret, safe=False)
        # TODO 这里需要数据库需要加锁
        ret = {
            'code': constant.BACKEND_CODE_CREATED,
            'message': '修改触发器成功'
        }
        return JsonResponse(ret, safe=False)

    @method_decorator(permission_required('monitor_web.delete_trigger', raise_exception=True))
    def delete(self, *args, **kwargs):
        """
        删除触发器
        """
        ret = {
            'code': constant.BACKEND_CODE_DELETED,
            'message': '删除触发器成功'
        }
        models.Trigger.objects.filter(id=self.request.query_params['id']).delete()
        return JsonResponse(ret, safe=False)

class expression_replace_callback0(object):
    """
    re.sub的回调函数，替换调原本表达式中item key成id
    """

    # 初始化属性
    def __init__(self, extra_arg):
        self.extra_arg = extra_arg

    # 使类的实例变得callable
    def __call__(self, match_obj):
        # 'proc.num[].avg(5m)'
        # 把监控项和函数以及参数入库
        item_function = match_obj.group(1)
        # >300
        operator_value = match_obj.group(2)
        m = re.match(r"(.*)\.([avg|last|diff|change]*)((.*))", item_function).groups()
        item_key = m[0]
        function_name = m[1]
        param = m[2].replace('(', '')
        param = param.replace(')', '')
        # 分别入库得到id
        old_item = models.MonitorItem.objects.filter(key=item_key, host_id=0).first()
        item_object, created = models.MonitorItem.objects.get_or_create(name=old_item.name, key=item_key, host_id=0,
                                                                        template_id=self.extra_arg['template_id'])
        function = models.Function.objects.create(name=function_name, parameter=param,
                                                  item=item_object,
                                                  trigger=models.Trigger.objects.get(id=self.extra_arg['trigger_id']))
        # 转换成{5}>300
        x = "{%s}%s" % (function.id, operator_value)
        return x


class expression_replace_callback4(object):
    """
    re.sub的回调函数，替换调原本表达式中item key成id
    """

    # 初始化属性
    def __init__(self, extra_arg):
        self.extra_arg = extra_arg

    # 使类的实例变得callable
    def __call__(self, match_obj):
        # 找到每个{}，维护function表，返回functionId，为了之后知道要被替换成什么
        pattern_exp = self.extra_arg['data']['pattern_exp']
        grp = re.match(pattern_exp, match_obj.groups()[0]).groups()
        item_key = grp[0]
        func_name = grp[1]
        params = grp[2]
        # 根据trigger表达式得知item_id
        itm = None
        if self.extra_arg['data']['host_id']:
            itm = models.MonitorItem.objects.filter(key=item_key, host_id=self.extra_arg['data']['host_id']).first()
        elif self.extra_arg['data']['template_id']:
            itm = models.MonitorItem.objects.filter(key=item_key, host_id=self.extra_arg['data']['template_id']).first()
        # 确定item_name，查或建item,获得item_id，function_name有了，param有了,item_id有了,trigger_id有了，完成修改
        function = models.Function.objects.get_or_create(name=func_name, parameter=params, item_id=itm.id,
                                                         trigger_id=self.extra_arg['data']['trigger_id'])[0]
        return '{%s}' % function.id


class MonitorItemNotInHostException(Exception):
    pass


@permission_classes((IsAuthenticated,))
class TriggerStatus(APIView):
    @method_decorator(permission_required('monitor_web.change_trigger', raise_exception=True))
    def put(self, request, pk=None, format=None):
        data = JSONParser().parse(self.request)
        ret = {
            'code': constant.BACKEND_CODE_OPT_FAIL,
            'message': '修改触发器状态失败'
        }
        try:
            models.Trigger.objects.filter(id=data['id']).update(status=data['status'])
            ret = {
                'code': constant.BACKEND_CODE_CREATED,
                'message': '修改触发器状态成功'
            }
        except Exception as e:
            print(traceback.format_exc())
        return JsonResponse(ret, safe=False)
